/**
 * @file        rl.hpp
 * @brief       GNU readline wrapper.
 *
 * @author      Emre Turkay <emreturkay at gmail>
 * @date        Nov.14.2008
 *
 * Copyright Emre Turkay 2009
 * Distributed under the Boost Software License, Version 1.0.
 * (See accompanying file COPYRIGHT or copy at
 * http://www.boost.org/LICENSE_1_0.txt)
 */

#include <stdio.h>
#include <readline/readline.h>

#include <boost/function.hpp>

#include <string>
#include <vector>

namespace rl
{

/// GNU readline wrapper interface.
struct reader
{
    /// Get the reader instance (singleton pattern).
    static reader& instance();

    /**
     * Read one line, with tab-completion support.
     * @arg eof     Set to true, if EOF matches.
     * @arg prompt  Character string to use as a prompt.
     * @return      Returns the line read.
     */
    std::string read(bool& eof, const char* prompt = 0);

    /// Sets the completer function.
    template <typename F>
    void completer(F f)
    {
        completer_ = f;
    }

private:
    /// Private constructor.
    reader();

    /// GNU readline completion function callback.
    static char** completion(const char* text, int start, int end);

    /// GNU readline entry function.
    static char* generator(const char*, int state);
    /// GNU readline noop entry function.
    static char* null_generator(const char*, int);

    /// The pointer to the instance.
    static reader* instance_;

    /// Keeps the matching strings.
    std::vector<std::string> matches_;

    /// The completer callback function.
    boost::function<std::vector<std::string>(const std::vector<std::string>&, bool)> completer_;

    /// Counts the completion strings.
    int generator_index_;
};

/// Return true if to_match partially matches with s.
inline bool part_matches(const std::string& to_match, const std::string& s)
{

    if (s.size() > to_match.size())
        return false;

    return (to_match.substr(0, s.size()) == s);
}

/// Fetches the matching strings.
inline std::vector<std::string>
fetch_matches(const std::string& s, const std::vector<std::string>& args)
{
    std::vector<std::string> result;
    for (std::vector<std::string>::const_iterator i = args.begin();
         i != args.end(); ++i)
    {
        if (part_matches(*i, s))
            result.push_back(*i);
    }
    return result;
}

} // namespace rl

